Как передать объект в событие onclick
Возможный дубликат:
Обработчики событий внутри цикла Javascript - нужно закрытие?
Я получаю некоторый объект json через вызов API. Он имеет следующий формат:-
{data:[{id:"1",name:"some1",url:"someurl1"},{id:"2",name:"some2",url:"someurl2"}...]}
Я получаю его через результат jsonp, и он анализируется, как показано ниже:
function(results){
for(var i=0;i<10;i++){
item=document.createElement("div");
item.innerHTML=results.data[i].name;
item.onclick=function(){
console.log(results.data[i]); //--->this is where i am stuck
}
}
}
Как передать конкретный объект из цикла в событие onclick. Я имею в виду, что первый созданный div должен иметь событие onclick с данными первого объекта, а второй div должен содержать данные из второго объекта. Пожалуйста, спросите меня, требуется ли какое-либо разъяснение?
Изменить:- Если я сделаю что-то вроде этого:-
item.onclick=function(){
console.log(results.data[1])
}
Я получаю этот конкретный объект в событии onclick всех предметов, но это не то, что я хочу
Изменить:- Вот как я наконец решил это. Благодаря ссылке, на которую указывает DCoder.
item.onclick =function(object){
return function(){
//do something with the object
}
}(obj);
6 ответов
Быстрое решение:
function(results){
for(var i=0;i<10;i++){
(function(index){ // create a closure, this makes a new scope
item=document.createElement("div");
item.innerHTML=results.data[index].name;
item.onclick=function(){
console.log(results.data[index]); //--->this is where i am stuck
}
})(i); // pass in i
}
}
Вы всегда можете использовать функцию данных jQuery для хранения и извлечения объекта данных:
function(results){
for(var i=0;i<10;i++){
item=document.createElement("div");
item.innerHTML=results.data[i].name;
// Store object in data
$(item).data("results", results.data[i]);
item.onclick=function(){
// Retrieve the data needed
var data = $(this).data("results");
console.log(data);
}
}
}
Добавьте скрытое поле внутри вашего div (созданного в цикле), оставьте в нем все, что вы хотите. затем по клику div. найдите скрытое поле внутри него (div) и прочитайте его значение.
Событие onclick вызывается из jquery, когда кто-то нажимает на "элемент". Вы не можете ожидать пользовательских данных для обработчика событий, если они не запущены с использованием функции триггера.
Я бы лично использовал $.map
поэтому функция обратного вызова создает новый контекст выполнения для каждой итерации.
Поскольку вы пометили вопрос с помощью jQuery, ваш код может быть таким простым, как:
$($.map(data, function(v, i) {
return $('<div>').html(data[i].name).click(function() {
console.log(data[i]);
});
})).appendTo('body'); //appending for demonstration purposes
Конечно, вы должны обернуть его внутри функции и передать data
массив объектов, как вы делали ранее.
У вас проблемы с асинхронными вызовами внутри js. Это распространенная проблема, и она описана здесь: http://dojo-toolkit.33424.n3.nabble.com/Advice-on-closures-and-retaining-variable-values-inside-async-handlers-e-g-xhrGet-td3227726.html
В основном значение i
равно 9
к тому времени, когда ваш console.log фактически запустится.
Есть много способов решить эту проблему в целом, но ваше конкретное решение, вероятно, должно состоять в огромной реструктуризации. Рассмотрим эту альтернативу (требуется jQuery), но мы могли бы сделать то же самое без нее очень легко.
$.each(results, function(data) {
var $el = $("<div></div>").html(data.name).click(function() { console.log(data) });
})
Но было бы еще лучше использовать jQuery.data() для хранения вещей, а затем использовать .on()
или же .delegate()
слушать события клика как это
$.each(results, function(data) {
var $el = $("<div></div>").addClass("yourThing").html(data.name).data("data", data);
})
// replace window with a closer parent if one exists
$(window).on("click", ".yourThing", function() {
console.log($(this).data("data")); // retrieve data from jquerys .data() store
});