I am having trouble changing a variable on a page with lots of PHP and JavaScript.
This part is working fine for me:
<script language="javascript" type="text/javascript">
function changebg(my)
{
document.getElementById("imglayer").style.backgroundImage ='url('+ my.src +')';
document.getElementById("cropframe").style.backgroundImage ='url('+ my.src +')';
}
var test2 = new String("url('+ my.src +')");
</script>
<img src="../../uploads/595MCoDFyArFFe.jpg" width="50" height="50" onclick="changebg(this)" >
<img src="../../uploads/P6l6J8aqzli6gh.jpg" width="50" height="50" onclick="changebg(this)" >
<img src="../../uploads/stXWS8fL4L3nvs.jpg" width="50" height="50" onclick="changebg(this)" >
with the div IDs being called for later.
My issue is I have another variable that I need to change dynamically:
<script type="text/javascript">
var test1 = new String( "<?php $src_name = '" );
var test2 = new String( "956ENbXjzTlkBo.jpg" );
var test3 = new String( "'; // modify this, original file?>");" );
document.write( String( test1, test2, test3 );
</script>
I need var test2 to change with the other two which are being grabbed by the div ID.
How do I change that string value? Is this even possible?
Any help would be greatly appreciated!
First of all, this is not Java (and even in Java you do not really need it). You should not use new String(…); simply use string literals:
var test1 = "…";
etc.
Second, strings are immutable; you cannot change a string value/object; you can only create and assign a new string. However, you can also create a user-defined Object instance that has a method that returns a value according to other values (like variable values):
var test2 = {
toString: function () {
return "foo" + test1 + "bar";
}
};
The document.write() DOM method implicitly converts its argument to string, which is done by calling either the hull object's toString() or valueOf() method, whichever is available first (see the ECMAScript Language Specification, 5.1 Edition, section 9.8). So
document.write(test2);
is equivalent to
document.write(String(test2));
(section 15.5.1) or
document.write(test2.toString());
It will write the return value of the toString() method of the object referred to by the value of test2. (For dynamic change of the output, you need to use other DOM features, such as the standards-compliant textContent, nodeValue, or the proprietary innerHTML property.)
BTW, the String constructor only considers one argument (see above), so new String(x, y, z) is equivalent to new String(x). Perhaps you were looking for concatenation: new String(x + y + z). But if at least one operand is of type String, x + y + z suffices; if not, String(x) + y + z or "" + x + y + z works.
Just use the right quotes:
var test2 = new String("url(" + my.src + ")");
Or simply:
var test2 = "url(" + my.src + ")";
However, you can't change a php variable by writing php code from Javascript. When the Javascript runs, the php script has aready ended.
First off, you're going a very weird way about building a string. I assume the point of this is to, at the end of all of this, end up with a string that looks like this:
<?php $src_name = 'X'; // modify this, original file ?>
(This outputs PHP, which won't be interpreted by your web server, but I'll assume you know that and you're outputting it for other reasons.)
Where x is some piece of data that's available in some other DOM element (one of your img elements, perhaps, since the filenames are similar). If you then want to, after some future arbitrary event occurs, update this x value that has been printed to the page. You'll need to give yourself some tangible element to update - for example, a span element.
Try document.write()ing this:
document.write("<?php $src_name = '<span id=\"my-element\">X</span>'; // modify this, original file ?>");
Note I've changed your < and > to their encoded equivalents.
Then, you can update the contents of your span using JavaScript at a later date (see below). This isn't changing the variable you have declared, but rather it is changing the contents of the page. Since you are just printing your string at the end of it all (or, trying to, since String() won't concatenate the given strings like you seem to think it will), it seems to me like this is what you're trying to accomplish.
document.getElementById("my-element").innerText = "NEW VALUE";
Again, this is not updating the variable, per se, just updating the text that you are printing to the page. This seems to be your end goal anyhow, correct me if I'm wrong.
Related
I have a var in script which has data like . But when i add this to another variable its not working.
var x = '32"';
onclick="javascript:selectSize(' + "'" + x + "'" + ');"
I want
onclick="javascript:selectSize('32"');"
But it becomes
onclick="javascript:selectSize('32"');""=""
i don't know whats happening
onclick="javascript:selectSize('32"');"
^ ^
The HTML parser will parse the attribute value before passing the value of it to the JS engine for execution.
You are using a " to delimit the attribute value.
The second " ends the attribute value.
If you want to use " as data in an attribute value delimited with " then you must express it as an entity (e.g. ").
var html_x = x.replace(/"/g, """);
Escaping becomes very painful when you start generating nested languages.
You have JavaScript embedded in HTML embedded in JavaScript.
Avoid mashing strings together to construct your DOM. Use DOM methods directly instead.
var x = '32"';
var button = document.createElement("button");
button.addEventListener("click", function (event) {
selectSize(x);
});
from comment, Make use of encode/decode URI Component as follows
var a=encodeURIComponent('abc"');
console.log(a);
console.log(decodeURIComponent(a));
I would like to create an HTML image element like this one:
<img src="www.example.com?param1=aid¶m2=sid¶m3=user¶m4=now" />
I tried doing this:
var now = new Date().getTime();
var aid = 123456;
var sid = 78910;
var user = "abcd";
How can I create the element from this data?
You create an img element (not "tag") using document.createElement('img').
You set its src, a string, using the src reflected property of that element. To create that string, for now, you'd use string concatenation (+). See below for an ES6 note, however.
So:
var img = document.createElement('img');
img.src = "www.example.com?param1=" + aid +
"¶m2=" + sid +
"¶m3 = " + encodeURIComponent(user) +
"¶m4=" + now;
Then you'd want to append that to the DOM somewhere.
Note the encodeURIComponent on the non-numeric one. Both the names and values in a query string must be URI-encoded. But I haven't bothered on param1, param2, etc. because I know that the URI-encoded version of them is...exactly the same. Similarly I know that the URI-encoded version of a number is just the number. But I see user is a text value, and I assume it isn't always "abcd", so to guard against issues I've URI-encoded it.
Re your comment:
And presumably if I'd like to add attributes to the img element it'd be like img.height=1 and img.width=1?
The specification lists the properties of img elements. Yes, both height and width are there and setting them has the same effect as using the height and width attributes, although you might want to use a stylesheet instead.
Not all attributes have reflected properties. For those that don't, you'd use setAttribute("name", value) (the value will be converted to a string if it isn't already one).
As of the next version of JavaScript, ECMAScript6 (ES6), you'd be able to use a template string for src instead:
var img = document.createElement('img');
img.src = `www.example.com?param1=${aid}¶m2=${sid}¶m3=${encodeURIComponent(user)}¶m4=${now}`;
Strings in JS can be chained together with the + operator. Number values will be coerced to strings (although that sometimes won't work as expected).
I am running into a problem people have posted before: JavaScript dynamic parameters
But my code uses nodes rather than innerHTML assignments, so the existing SO post doesn't seem to apply to my code.
I want to dynamically generate HTML buttons in a table. For each button, I want to call a function with parameters that depend on the button's index/position in the table. First I tried just using lambda functions with the variable over which I was incrementing. This didn't work, so I also tried dynamically named variables, meaning each button should be passing a differently named variable to deal with lazy-loading effects. But this didn't work either. You can see both versions of what I tried in the code below:
This code I paste below is in a for-loop. In the following, I increase i by 1 each time. offset and jj are unchanged within the loop.
var variableDynamic = i.toString();
window['variableName' + variableDynamic] = i + offset;
upvote.onclick = function() {
upVoteA(i + offset, jj);
//upVoteA(window['variableName' + variableDynamic] , jj);
};
upvote.innerHTML = "Upvote"
Someone told me to look into closures, so following this recommendation: http://www.usepatterns.com/blog/javascript-closures I rewrote the onclick function declaration as:
upvote.onclick = function() {
var a = i + offset;
var b = kk;
function closeIt(){
upVoteA(a,b);
}
closeIt();
};
This still has the same effect that every button calls upVoteA with the same parameter, namely the last/highest value.
I realize I could refactor my code to turn these into .innerHTML set statements and then I'd print the variable and it would be set as a printed statement instead of a lazily-loaded variable. But I'd like not to do that if possible. (apologies that it's not technically lazy loading, the name seems reasonably apt)
Is there a way to make my code work? And why are the closures failing? I thought closures should preserve the environment they were created in, but that is not the case with my code. Which portion of the "environment" are preserved with closures?
This is a very bad answer, but it works
var funcStr = "function dummy() { upVoteA(" + (i + offset) + "," + jj + "); }";
eval(funcStr);
upvote.onclick = dummy;
But if you have something better, please let me know.
If I have the following:
<p class="demo" id="first_p">
This is the first paragraph in the page and it says stuff in it.
</p>
I could use
document.getElementById("first_p").innerHTML
to get
This is the first paragraph in the page and it says stuff in it.
But is there something simple you can run which would return as a string
class="demo" id="first_p"
I know I can iterate through all of the element's attributes to get each one individually but is there a function which returns tagHTML or something like that?
The following code is something of a mouthful: I wrote it as a one-liner, but I've broken it out into several lines here. But this will get you a plain object where the keys are attribute names and the values are the values of the corresponding attributes:
Array.prototype.reduce.call(
document.getElementById('first_p').attributes,
function (attributes, currentAttribute) {
attributes[currentAttribute.name] = currentAttribute.value;
return attributes;
},
{}
);
Going through this, document.getElementById('first_p').attributes gets you a NamedNodeMap of the element's attributes. A NamedNodeMap is not an Array, but Array.prototype.reduce.call(...) calls Array.prototype.reduce on the NamedNodeMap as if it were an Array. We can do this because NamedNodeMap is written so that it can be accessed like an array.
But we can't stop here. That NamedNodeMap that I mentioned is an array of Attr objects, rather than an object of name-value pairs. We need to convert it, which is where the other arguments to Array.prototype.reduce come into play.
When it's not being called in a strange way, Array.prototype.reduce takes two arguments. The second argument (which is third for us because of the way we called it) is an object that we want to build up. In our case, that's a brand-new bare object: the {} that you see at the end.
The first argument to Array.prototype.reduce (which, again, is second for us) is another function. That function will get called once for each item in the loop, but it takes two arguments. The second argument is the current loop item, which is easy to understand, but the first argument is a little wild. The first time we call that function, its first argument is the object we want to build up (i.e. the last argument to Array.prototype.reduce. Each time after that, the first argument is whatever that function returned the last time it was called. Array.prototype.reduce returns whatever the last call to its inner function returned.
So we start with an empty object. Then for every Attr in the element's attributes, we add something to the object, and return it. When the last call finishes, the object is finished, so we return that. And this is how we make the attribute list.
If you wanted the exact code in the tag, like a String, then I'm afraid there is no standard function to get that exactly. But we can get a close approximation of that code, with a similar setup:
Array.prototype.map.call(
document.getElementById('first_p').attributes,
function (currentAttribute) {
return currentAttribute.name + '=' + JSON.stringify(currentAttribute.value);
}
).join(' ');
The basic principle is the same: we take that NamedNodeMap and call an Array function on it, but this time we're using map instead of reduce. You can think of map as a special case of reduce: it always builds up an Array, with one element for every element that was in the original. Because of that, you don't even need to mention the object you're building up: the callback function only has one argument, and we just return the thing to put into the new Array. Once we're done, we have an Array of 'name="value"' strings, and then we just join that with ' '.
It isn't a built-in property, but you can use the array-like object attributes to obtain what you're looking for.
Array.prototype.map.call(element.attributes, function (el) {
return el.name + '="' + el.value + '"';
}).join(' ')
This is assuming a browser that supports the map function. The Array.prototype.map.call part is because attributes is not really an array and does not have a join method, but because it's an array-like JavaScript's dynamism allows us to call map on it anyway.
Example from the current page with the footer div:
var element = document.getElementById('footer')
Array.prototype.map.call(element.attributes, function (el) {
return el.name + '="' + el.value + '"';
}).join(' ');
// "id="footer" class="categories""
You can try the following:-
var attributes = '';
for(var i=0; i<document.getElementById("first_p").attributes.length; i++){
var attr = document.getElementById("first_p").attributes[i];
attributes += attr.nodeName+"='"+attr.nodeValue+"' "
}
console.log(attributes);
You can use document.getElementById("first_p").attributes to get an array of all the attributes on that DOM element
If you wanted them all in one string just do: document.getElementById("first_p").attributes.join(' ') to get the desired output
Well, while nothing currently exists to do this directly (though the approaches using the Node's attributes is a more reliable approach, one option is to create this method yourself:
HTMLElement.prototype.tagHTML = function(){
// we create a clone to avoid doing anything to the original:
var clone = this.cloneNode(),
// creating a regex, using new RegExp, in order to create it
// dynamically, and inserting the node's tagName:
re = new RegExp('<' + this.tagName + '\\s+','i'),
// 'empty' variables for later:
closure, str;
// removing all the child-nodes of the clone (we only want the
// contents of the Node's opening HTML tag, so remove everything else):
while (clone.firstChild){
clone.removeChild(clone.firstChild);
}
// we get the outerHTML of the Node as a string,
// remove the opening '<' and the tagName and a following space,
// using the above regular expression:
str = clone.outerHTML.replace(re,'');
// naively determining whether the element is void
// (ends with '/>') or not (ends with '>'):
closure = str.indexOf('/>') > -1 ? '/>' : '>';
// we get the string of HTML from the beginning until the closing
// string we assumed just now, and then trim any leading/trailing
// white-space using trim(). And, of course, we return that string:
return str.substring(0,str.indexOf(closure)).trim();
};
console.log(document.getElementById('test').tagHTML());
console.log(document.getElementById('demo').tagHTML());
JS Fiddle demo.
http://jsfiddle.net/zzTsc/
I have a JSON that holds some values which get concatenated into a string but when I change the value of the JSON the string doesn't take the name values. How can I make the string take the new values without re-declaring the same string?
See I could easily put string = name.first + "<br />"+name.last; right below where I change the JSON value but then when I wanna edit the format of that string I'll have to change it twice.
That's not how variables work. You have to set the value of string again for it to update.
Here's an improved version so you don't have to change it twice if you want to edit something:
function generateString(name) {
return name.first + "<br />"+name.last;
}
var string = generateString(name);
Demo
That's not going to work as you describe it, but you could declare a function which returns the appropriate string.
So instead of
string = name.first + "<br />" + name.last;
You'd have:
var stringfunction = function() {return name.first + "<br />" + name.last;}
and when you wanted to use it you'd call it:
alert(string); //old
alert(stringfunction()); //new
EDIT: I just realized you're talking about changing the format (presumably at runtime). There are a number of ways to use string formats in javascript, meaning that you could have a "format" variable used inside the stringfunction, which you could change at runtime to modify how the resulting string is formatted. It's been too long since I used one of those tools though, so I'll leave it to someone else to explain how to do string formatting in javascript.
This is because your string is a basic type and therefore holds the actual data instead of a pointer. When you change the data you think should change the string, it only changes the data. This can be seen by just re-issuing the code used to construct the string
$('#test').empty().append(name.first + "<br />"+name.last);
http://jsfiddle.net/zzTsc/4/