I have an object, X, and some code that creates a div and assigns id = X.ID. After the html is created, I assign the object to the div, like this:
document.getElementById(X.ID).XValue = X;
If I set a break after that statement, I can evaulate document.getElementById(X.ID).XValue and see all the properties of X.
While I was creating the html, I added onmouseup="MOUSE_UP(event)".
var aProp = {};
aProp.ThisValue = "This";
aProp.ThatValue = "That";
aProp.Id = 5;
var html = '<div id="' + aProp.Id + '"';
var func = 'MOUSE_UP';
html += ' onmouseup="' + func + '(event) ">';
html += '</div>';
document.getElementById("test").innerHTML += html;
document.getElementById(aProp.Id).XVALUE = aProp;
function MOUSE_UP(event) {
alert(event.currentTarget.XValue.ThisValue);
}
Now, when I set a break at MOUSE_UP, event.currentTarget is my div (event.currentTarget.id == X.ID), but event.currentTarget.XValue is undefined.
Why is XValue undefined here when it was defined earlier?
Looks like setting innerHTML of #test would wipe out all custom properties from its children. You can check this in the jsFiddle. When you'll run the fiddle as it is, you'll notice NewProp of #1 will become undefined after adding more content with test.innerHTML += ... If you log tabIndex instead of NewProp, you'll get the correct values.
This happens because += operator is just a shortcut for a statement like a = a + b, which can also be written a += b.
Basicly you create a string from the inner HTML of #test, then add another string to it, and finally replace the original innerHTML of #test with this new string. All previous elements in #test are replaced with new ones, which don't have the custom properties set.
When setting id property for an element, also id attribute is added to the HTML, hence they are a part of innerHTML of #test, and are added to the newly created HTML too.
If you use proper DOM manipulation instead of setting innerHTML, you'll get the results you want. The code below uses createElement() and appendChild() methods instead of setting innerHTML.
function myMouseUp(e) {
alert("at MouseUp " + e.currentTarget.NewProp.ThisValue);
}
function buildOneDiv(aProp) {
var html = document.createElement('div');
aProp.ThisValue = 'This is ' + aProp.id;
aProp.ThatValue = 'That is ' + aProp.id;
html.id = aProp.id;
html.addEventListener('mouseup', myMouseUp, false);
html.innerHTML = 'Test ' + aProp.id;
return html;
}
function buildDivs(x) {
var html = buildOneDiv(x);
document.getElementById("test").appendChild(html);
document.getElementById(x.id).NewProp = x;
}
window.onload = function () {
var aProp, i;
for (i = 1; i < 4; i++) {
aProp = {};
aProp.id = i;
buildDivs(aProp);
}
};
A live demo at jsFiddle.
This is not so much an answer as it is a clarification and a work-around.
Given this html
<div id="test"></div>
and this code
function myMouseUp(e) {
alert("at MouseUp " + e.currentTarget.NewProp.ThisValue);
}
function buildOneDiv(aProp) {
aProp.ThisValue = "This";
aProp.ThatValue = "That";
var html = '<div id="' + aProp.id + '"';
var func = 'myMouseUp';
html += ' onmouseup="' + func + '(event) ">';
html += 'Test ' + aProp.id + '</div>';
return html;
}
function buildDivs(x) {
var html = buildOneDiv(x);
document.getElementById("test").innerHTML += html;
document.getElementById( x.id ).NewProp = x;
}
window.onload = function () {
for (var i = 1; i < 4; i++) {
var aProp = {};
aProp.id = i;
buildDivs(aProp);
}
};
The end result is that only the LAST div whose onmouseup is defined will have a legitimate value for NewProp at myMouseUp. For each other div, this property is undefined. This is why I got some comments indicating that "It does work." It works for ONE, which is all I had in my example. (This is the clarification.)
My workaround is to add a global object to be an associative array and change two statements:
var myDivs = {}; // global
Replace
document.getElementById( x.id ).NewProp = x;
in buildDivs with
myDivs[x.id] = x;
and replace
alert("at MouseUp " + e.currentTarget.NewProp.ThisValue);
in myMouseUp with
alert(myDivs[e.currentTarget.id].ThisValue );.
I'd still like to know why the original approach doesn't work.
Related
I'm appending some html into a list, but having trouble passing the selected_files.name value into the function. Please see the onclick below
for (var i = 0; i < selected_files.length; ++i) {
children += '<div class="del" onclick="javascript:removeImageFromList(selected_files[i].name)">X</div>' + selected_files[i].name + '<br>';
}
What is the proper way to pass this in? When I log from inside the removeImageFromList function it is receiving a selected_files[i].name as a string rather than the value.
You can use template string. It would be easy to read and You can get rid to remember where to add + and "".
Just for example I've simulated selected_files as an array with name property.
const selected_files = [{ name: "first"}, {name: "second"}];
let children = "";
for (var i = 0; i < selected_files.length; ++i) {
children += `<div class="del" onclick="javascript:removeImageFromList(${selected_files[i].name})">X</div>${selected_files[i].name}<br>`;
}
console.log( children );
To pass the value contained in the object, you need to do what you did later in the string:
children += '<div class="del" onclick="javascript:removeImageFromList(' + selected_files[i].name + ')">X</div>' + selected_files[i].name + '<br>';
please try the below code snippet
var selected_files=[{name:'abc'}, {name:'xyz'}]
var children='';
for (var i = 0; i < selected_files.length; ++i) {
children += '<div class="del" onclick="javascript:removeImageFromList(\''+selected_files[i].name+'\')">X</div>' + selected_files[i].name + '<br>';
}
console.log('children--->',children);
You just need to move your function-call-variable outside the string like you already did at the end.
Like this:
for (var i = 0; i < selected_files.length; ++i) {
children += '<div class="del" onclick="javascript:+removeImageFromList('+selected_files[i].name)+'">X</div>' + selected_files[i].name + '<br>';
}
Your code has two problems:
you are appending html (a div) as a string, which is prone to spelling errors. your editor won't correct strings but it will correct javascript.
you are actually adding javascript inside that string. I would say that is a definite no-no in code land....
You can solve this problem by creating DOM elements the javascript way. Then you can add an eventListener to respond to mouse clicks.
let selected_files = [{name:"henk"},{name:"wim"}]
for (let i = 0; i < selected_files.length; i++) {
let div = document.createElement("div")
div.classList.add("del")
div.innerText = selected_files[i].name
div.addEventListener("click", ()=>{
removeImageFromList(selected_files[i].name)
})
document.body.appendChild(div)
}
function removeImageFromList(str){
console.log(str)
}
I have something that I can't understand and i'm struggling with that for 2 days.
For the story, I'm using VICOPO api to get zipcode/city (France only I think).
The thing is that the code I'm generating is not really good interpreted by jQuery (or maybe I'm doing it wrong)
Here is the code:
$('#postcode').val($('#postcode').val().toUpperCase());
if ($('#postcode').val().length == 5)
{
var $ville = $('#postcode');
$.vicopo($ville.val(), function (input, cities) {
if(input == $ville.val() && cities[0]) {
if (cities.length == 1)
$('#city').val(cities[0].city);
else
{
var html = '';
html += '<div style=\'text-align:center\'>';
for (var i=0; i<cities.length; i++)
{
var v = cities[i].city;
// --- HERE IS MY PROBLEM ---
html += '<p onclick=\'alert(\'' + v + '\');\'>' + v + '</p>';
}
html += '</div>';
console.log(html);
$('#multi_ville').html(html);
}
}
});
When I inspect the elements in the multi_div this is what I get:
<p onclick="alert(" billey');'>BILLEY</p>
<p onclick="alert(" flagey-les-auxonne');'>FLAGEY-LES-AUXONNE</p>
etc ....
And when I inspect the console log, all looks correct:
<p onclick='alert('BILLEY');'>BILLEY</p>
<p onclick='alert('FLAGEY-LES-AUXONNE');'>FLAGEY-LES-AUXONNE</p>
<p onclick='alert('VILLERS-LES-POTS');'>VILLERS-LES-POTS</p>
etc ....
If someone have an idea or what I'm doing wrong, it would cool.
(may I mention, this code is in a smarty tpl file surrounded with the {literal} tag)
Try to create self closed tags via jquery and then append them to #multi_ville, here is an example:
// create div element
var div = $('<div/>', {
'style' : 'text-align:center'
});
for (var i=0; i<cities.length; i++)
{
var v = cities[i].city;
// create p element with click event and then append it to div
$('<p/>').on('click', function() {
alert(v);
}).text(v).appendTo(div);
}
$('#multi_ville').append(div);
EDIT It seems that my code above always alert the last city when we click on a element, that's because alert takes the value that v variable has at the time it runs, to solve this we can use let statement:
let v = cities[i].city;
Or a function:
for (var i=0; i<cities.length; i++) {
var v = cities[i];
createPTag(v, div);
}
function createPTag(v, div) {
$('<p/>').on('click', function() {
alert(v);
}).text(v).appendTo(div);
}
Instead of
html += '<p onclick=\'alert(\'' + v + '\');\'>' + v + '</p>';
try this:
html += '<p onclick="alert(\'' + v + '\');">' + v + '</p>';
Here's some info on when and how to use double/single quotes.
EDIT:
Also, check the else on this if statement:
if (cities.length == 1)
You need a closing curly bracket (}) to close in the else. It should be added directly after this line:
$('#multi_ville').html(html);
In the following code, links_container.innerHTML = links; outputs http://localhost/pagination/js-pagination.html# instead of <a href='#'>Page 1</a>.
HTML
<div class="pagination-links"></div>
JS
function createLinks() {
var links_container = document.getElementsByClassName('pagination-links')[0];
for(i=1; i<=5; i++){
var link = document.createElement('a');
var txt = document.createTextNode('Page ' + i + " ");
link.setAttribute("href", "#");
link.appendChild(txt);
links_container.innerHTML = link;
}
}
Can anybuddy explain. why
innerHTML is a string property and thus takes a string as value. Your link is an element object and because of this it's implicitly converted to a string with its toString() method, which does indeed return the URL.
Here are two ways you can fix this:
Both of these solutions require you to clear the container before the for loop by running links_container.innerHTML = ''
Append the element with links_container.appendChild(link)
Use the outerHTML of the element object: links_container.innerHTML += link.outerHTML
The first option is the more appropriate one as it inserts the DOM element you created into the DOM directly. The second option converts your DOM element to a string and then forces the browser to create a new DOM element from that HTML. If there had been any event listeners added to the element they would've been lost.
Instead of setting innerHTML try calling appendChild. The link object is an element not an HTML string.
i.e. try changing:
links_container.innerHTML = links;
to
links_container.appendChild(link);
function createLinks() {
var links_container = document.getElementsByClassName('pagination-links')[0];
// clear out previous html
links_container.innerHTML = "";
for (i = 1; i <= 5; i++) {
var link = document.createElement('a');
var txt = document.createTextNode('Page ' + i + " ");
link.setAttribute("href", "#");
link.appendChild(txt);
// append link to container
links_container.appendChild(link);
}
}
createLinks();
<div class="pagination-links"></div>
Solution using innerHTML:
links_container.innerHTML += link.outerHTML;
or
links_container.innerHTML += "<a href='#'>Page " + i + " </a>"
function createLinks() {
var links_container = document.getElementsByClassName('pagination-links')[0];
// clear out previous html
links_container.innerHTML = "";
for (i = 1; i <= 5; i++) {
var link = document.createElement('a');
var txt = document.createTextNode('Page ' + i + " ");
link.setAttribute("href", "#");
link.appendChild(txt);
// add link
links_container.innerHTML += link.outerHTML;
// or you can use this instead of the above code
//links_container.innerHTML += "<a href='#'>Page " + i + " </a>";
}
}
createLinks();
<div class="pagination-links"></div>
Replace this line
links_container.innerHTML = links;
with
links_container.innerHTML = link;
as you do not have any links variable there.
I am building a context menu with some options using <li> tags as shown below. I need to simulate click event on another ID (image), When i choose and click on this option from context menu.. I can only have the function instantaneous execution inside onclick as shown in below code-
Edited the code to give more clarity
var functionMain = function ContextMenu$functionMain(items, targetId) {
$(menu).html(buildItems(items, targetId));
};
var buildItems = function ContextMenu$buildItems(items, targetId) {
var i, result;
result = '';
for (i = 0; i < items.length; ++i) {
var reportId = targetId.substring(targetId.indexOf(':') + 1);
var reportIdFormed = $('#' + reportId + 'run' + runReportLinkName);
result += '<li> Run HTML </li>';
}
return result;
};
Above code is resulting in Uncaught SyntaxError: Unexpected identifier
Resultant HTML --> Run HTML
How to get rid of this issue?
Use a delegated event
var reportId = targetId.substring(targetId.indexOf(':') + 1);
var reportIdFormed = $('#' + reportId + 'run' + runReportLinkName);
result += '<li> Run HTML </li>';//add a class
$('body').on('click','.delegated-event',function(){ //delegate the event based on that class
reportIdFormed.trigger('click');
})
if the selector changes for each element then you need a attribute to store the selector:
var reportIdFormed = '#' + reportId + 'run' + runReportLinkName;//make it a string
result += '<li> Run HTML </li>';//add a class
$('body').on('click','.delegated-event',function(){ //delegate the event based on that class
reportIdFormed = $($(this).attr('data-selector'));//get the selector
reportIdFormed.trigger('click');
})
The problem with your code is that you are trying to pass and object referent instead and ID string, so you are printing that, so JS cannot print and JS object, so it will print the reference [object Object] so you should do it like so:
var reportId = targetId.substring(targetId.indexOf(':') + 1); //e.g. rpt1234
var reportIdFormed = '#' + reportId + 'run' + runReportLinkName; //e.g. rpt1234runHTML
result += '<li> Run HTML </li>';
Your code JS
function handleTrigger(id) {
var target = $(id);
if (target.length) {
target.trigger("click")
}
}
Try this
var reportId = targetId.substring(targetId.indexOf(':') + 1); //e.g. rpt1234
var reportIdFormed = reportId + 'run' + runReportLinkName; //e.g. rpt1234runHTML
result += '<li> Run HTML </li>';
Is there simple any way to get an element's starting tag in javascript as string?
Suppose I have a DOM node which is a html element in a variable, I would like write something similar:
var tagName = element.tagName; //Works
var startingTag = element.startingTag; // Is there any way?
var startingTag = getStartingTag(element); // Or do I have to write my own function?
Thx for answers
For example this is a starting tag I would like to get into a string:
<Table class="anyClass" width="100" ... >
where the tagName only gives this: "Table"
Well, you could do:
var elStr = element.outerHTML
,startTag = elStr.substr(0,elStr.indexOf('>')+1);
Or use the element.attributes if you need information about attributes
You can loop through the attributes and append them to some string.
function getStartingTag(elem)
var str = '',
attr = elem.attributes,
value;
// Beginning of tag. toLowerCase() for a cleaner string.
str += '<' + elem.nodeName.toLowerCase() + ' ';
for (var i = 0, l = attr.length; i < l; i++) {
// Safety check.
value = attr[i].nodeValue.replace('"', '\\"');
// Append the name + value of the attribute.
str += attr[i].nodeName + '="' + attr[i].nodeValue + '" ';
}
str += '>';
return str;
}