Reputation: 111
I have a group of <span>
elements that is created dynamically in a JavaScript function. Each <span>
that is created I want to be clickable and call a function that takes the parameter as object on click.
My problem is when I pass the object I get the error undefined
for objAddQuestion
. How can I pass the object to the function?
for (var j = 0; j < lstQuestions.length; j++) {
var objAddQuestion = new Object();
objAddQuestion = lstQuestions[j];
html += ' <span onclick="addQuestion(objAddQuestion)" class="badge addQ">' +
' Add</span>';
}
and the function:
function addQuestion(obj) {
//I got error when click
}
lstQuestions
is a list of objects.
Upvotes: 0
Views: 185
Reputation: 82
If object are global try with:
function addQuestion(obj) {
window[obj];
}
for local objects try e.g.:
function addQuestion(obj) {
lstQuestions[obj];
}
and:
for (var j = 0; j < lstQuestions.length; j++) {
var objAddQuestion = new Object();
objAddQuestion = lstQuestions[j];
html += ' <span onclick="addQuestion('+j+')" class="badge addQ">' +
' Add</span>';
}
Upvotes: 0
Reputation: 1074295
You've said that lstQuestions
is a list of objects. That means you probably don't want to embed the question in an onclick
attribute handler.
Instead, I'd suggest using modern event handling, not onclick
attributes. For instance, I'd probably do this by including a question identifier on the span
and then handling the event with event delegation.
Note: You've tagged your question jquery, but there's no jQuery apparent in your question, so I haven't used it in this first solution. You certainly could, though, and the delegation would be simpler; see under the horizontal line below.
var lstQuestions = [
{
id: 1,
text: "Question 1",
details: "Details for question 1"
},
{
id: 2,
text: "Question 2",
details: "Details for question 2"
},
{
id: 3,
text: "Question 3",
details: "Details for question 3"
}
];
var html = "";
for (var j = 0; j < lstQuestions.length; j++)
{
// Include the question ID (or if the list never changes, just use `j`) as a data-* attribute
var question = lstQuestions[j];
html += ' <span data-question="' + lstQuestions[j].id + '" class="badge addQ">' +
question.text +
' Add</span>';
}
document.getElementById("questions").innerHTML = html;
// Handle clicks on the container
document.getElementById("questions").addEventListener("click", function(e) {
// Did the click pass through a span.addQ?
var span = e.target.closest("span.addQ");
if (span && this.contains(span)) {
// Yes, get its ID
var id = +span.getAttribute("data-question");
// Find the question
var question = lstQuestions.find(function(q) { return q.id === id; });
if (question) {
console.log("Question details: " + question.details);
}
}
});
<div id="questions"></div>
Using jQuery, you might go with Rory's approach using jQuery's element data cache. But here's the above using jQuery rather than using the DOM directly:
var lstQuestions = [
{
id: 1,
text: "Question 1",
details: "Details for question 1"
},
{
id: 2,
text: "Question 2",
details: "Details for question 2"
},
{
id: 3,
text: "Question 3",
details: "Details for question 3"
}
];
var html = "";
for (var j = 0; j < lstQuestions.length; j++)
{
// Include the question ID (or if the list never changes, just use `j`) as a data-* attribute
var question = lstQuestions[j];
html += ' <span data-question="' + lstQuestions[j].id + '" class="badge addQ">' +
question.text +
' Add</span>';
}
$("#questions")
.html(html)
.on("click", "span.addQ", function() {
// Yes, get its ID
var id = +this.getAttribute("data-question");
// Find the question
var question = lstQuestions.find(function(q) { return q.id === id; });
if (question) {
console.log("Question details: " + question.details);
}
});
<div id="questions"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Upvotes: 4
Reputation: 337560
To achieve this you can store the object in jQuery's data
cache on each span
that you create. Then you can use an unobtrusive delegated event handler to read them back out again when the element is clicked. Try this:
var lstQuestions = [
{ label: 'foo' },
{ label: 'bar' },
{ label: 'fizz' },
{ label: 'buzz' }
];
var spans = lstQuestions.map(function(o) {
return $('<span />', {
'class': 'badge',
'text': o.label
}).data('question', o);
})
$('#questions').on('click', '.badge', function() {
var obj = $(this).data('question');
console.log(obj);
}).append(spans);
span {
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="questions"></div>
Another alternative would be to store the index of the related object of the array in the data attribute and then use that to retrieve the item from the array when the element is clicked. Either has advantages, it depends on your use case as to which is more appropriate.
Upvotes: 4
Reputation: 3090
You may want to generate the span
elements one by one, then append it to your container
var container = document.getElementById( 'container' );
var lstQuestions = [
'Question A'
, 'Question B'
, 'Question C'
];
for (var j = 0; j < lstQuestions.length; j++)
{
var objAddQuestion = lstQuestions[j];
var span = document.createElement( 'span' );
span.onclick = generateClickMethod( objAddQuestion );
span.classList.add( 'badge', 'addQ' );
span.innerText = ' Add ';
container.appendChild( span );
}
function generateClickMethod( obj ){
return function(){
addQuestion( obj );
};
}
function addQuestion( obj ){
alert( obj );
}
<div id="container"></div>
Upvotes: 3