JQuery click eventhandler: register event on dynamically added element - javascript

I would like to dynamically build a page from 2 hashes (in my example c and d).
var c = {
cluster_1 : { list_datasets: [ "a", "b", "c"]},
cluster_2 : { list_datasets: [ "b", "c"]},
};
var d = {
a : { title: "A", content: "aaaaaaaaaaaaaa"},
b : { title: "B", content: "bbbbbbbbbbbbbb"},
c : { title: "C", content: "cccccccccccccc"},
};
so that I first get the list of clusters, and then by clicking on the cluster, I get the list of their respective content. This works fine until here.
But now if I want to go a step further end by clicking on each dataset, I would like to have the dataset description. The jquery selection operation $('#a') is empty and nothing is shown. Here a little standalone example that shows the problem
Thanks a lot for you help or any information on that topic.
Kind regards
Antoine

Since these elements are created dynamically, you have to use delegate event handler like
$(document).on('click', '#'+key, function(event){
$("aside").html(value.content);
});
JSFiddle

Your problem is that you call second each
$.each(d, function(key, value){ ..
when there are no elements printed on the page.
Elements get printed only when you click on any of clusters. So you should wrap second each with a function e.g.
function getValues(){
$.each(d, function(key, value){
$('#' + key).each(function(){
console.log(value.content);
});
});
};
and call it at the end of click function
$('#' + cluster).click(function( event ) {
var content_list = "<ul>";
for (var i = 0; i < value.list_datasets.length; i++) {
var dsName = datasetName = value.list_datasets[i];
if(d.hasOwnProperty( datasetName ) ) {
var datasetName = d[datasetName].title;
}
content_list = content_list + "<li><a id='" + dsName + "' href='#foo'>" + datasetName + "</a></li>";
}
content_list = content_list + "</ul>";
$("section").html(content_list);
getValues();
});

Related

JavaScript loop inside tinymce button

My JavaScript loop is not working properly inside a tinymce button.
I set a variable n which is the array size that I get from my html input.
var n = $('#total').val();
Then, I create the array of tinymce buttons: var menuItems = [];
In my tinymce editor init, I create the buttons:
editor.on('init', function (e) {
for (var i=1; i<=n; i++){
var obj = {
text: 'Item ' + i,
onclick: function() {
var msg = ' <strong>#item' + i + '#</strong> ';
editor.insertContent(msg);
}
}
menuItems.push(obj);
}
});
Last step is add the menuItems to the tinymce buttons:
editor.addButton('myButton', {
type: 'menubutton',
text: 'Items',
icon: false,
menu: menuItems
});
The buttons are displaying correct with the correct label. I have the buttons:
Item 1
Item 2
Item 3
However, doesn't matter which button I click, the text displayed in the editor is item3. It always get the last button text.
Does anyone know why it is happening?
Thanks
Use let instead of var since let would keep its lexical block scope where var would not:
editor.on('init', function(e) {
for (let i = 1; i <= n; i++) { // <-- use let here
var obj = {
text: 'Item ' + i,
onclick: function() {
var msg = ' <strong>#item' + i + '#</strong> ';
editor.insertContent(msg);
}
}
menuItems.push(obj);
}
});
Here is the documentation on let

add attribute to input from array; however, using value pair from jsaon

I'm getting error: setAttribute' on 'Element': 2 arguments required, but only 1 present.
I want to add attributes to an input but i'm avoiding repeats:
//putHolder.setAttribute("placeholder", "Product Name (required)");
//putHolder.setAttribute("ng-model", "vm.product.productName");
//putHolder.setAttribute("ng-minlength", "4");
//putHolder.setAttribute("ng-maxlength", "12");
//putHolder.removeAttribute("size");
I have used the following code but i can't get it right:
var putHolder = document.getElementById('CustomerID');
//var result = '{"placeholder":"Product Name (required)","ng-model":"vm.product.productName","ng-minlength":"4", "ng-maxlength":"12"}';
//$.each($.parseJSON(result), function (k, v) {
// putHolder.setAttribute(k + ' = ' + v);
// });
//or js please i prefer javascript
JSON.parse('{"placeholder":"Product Name (required)","ng-model":"vm.product.productName","ng-minlength":"4", "ng-maxlength":"12"}', function(k, v) {
putHolder.setAttribute(k + ' = ' + v);
});
I've also tried a loop but is just 1 elem like so:
var names = ["size", "value"];
for (var i = 0; i < names.length; i = ++i) {
var cadaUno = names[i];
putHolder.removeAttribute(cadaUno);
}
I hope someone can help thanks.

JSON Object (how to not load the entire object on DOM initially)

So i am reading a local json file that consist of {[Object,Object,Object.....]}
I am using the
$.getJSON('products.json', function (pdata) {
for (var i = 0; i < pdata.data.length; i++) {
AppendtoDom(pdata.data[i]);
}
The above code reads the json objects and appends to the DOM, but i want to initially load only 100 objects at a time and on scroll keep appending.
Say there are around 1200 objects. How do i go about this?
My implementaion so far
$(function(){
loadData();
});
function loadData(){
$.getJSON('products.json', function (pdata) {
var i = 0;
function addtoDom(num){
var limit = Math.min(i + num, pdata.data.length);
for(; i < limit; i++){
getInformation(pdata.data[i]);
}
}
addtoDom(100);
$('.content').jscroll({
callback: addtoDom(100)
});
});
}
function getInformation(obj){
var content = "";
for (var i = 0; i < 4; i++) {
content += '<li>';
content += "<img src='" + obj.imageUrl + "' style='width:200px;height:200px'/>";
content += '<div class="productName">' + obj.fullName + "</div>";
content += '<div class="price">Price: ' + obj.price + "</div>";
content += '</li>';
}
$("<ul class= 'view'>" + content + "</ul>").appendTo('.content');
}
Similar question i asked in How would i implement an infinite scroll in my DOM
You can put all the objects you get back from the Ajax call into a persistent variable, add the first 100 to the DOM, keep a counter of how many you've added so far and then upon scrolling to a certain point, add another 100, add another 100 and so on.
$.getJSON('products.json', function (pdata) {
var i = 0;
function addMore(num) {
var limit = Math.min(i + num, pdata.data.length);
for (; i < limit; i++) {
AppendtoDom(pdata.data[i]);
}
}
// add the first 100
addMore(100);
// then set up whatever scroll detection you want here and
// when you decide that it has scrolled enough to add some more
// you just call addMore(100) again
});
In your specific implementation of the above idea, you have an implementation mistake. You have to pass a function reference for the callback so change this:
$('.content').jscroll({
callback: addtoDom(100)
});
to this:
$('.content').jscroll({
callback: function() {addtoDom(100);}
});
Assign your JSON to a variable and dynamically render them as needed.
var json;
$.getJSON('products.json', function (pdata) {
JSON = pdata;
};
// Scheduling logic
AppendtoDom(json[i]);

Create a list from selected list items

I have a fiddle here: my fiddle. What I am trying to do is create a list of items from a separate group of lists. I cannot seem to get a grasp on what I am doing wrong, but here is whats happening:
I have a group of lists based on tabular data
Each list has the name of the column and a selection checkbox
If I select an item, it needs to be added to the selected columns area (vertical list)
There are 14 unique tabular items with checkboxes
(PROBLEM -->) When I select an item, it gets added 14 times in the selected columns section
code
(html):
I tried ti insert HTML but is not working right. Please look at the fiddle listed above.
(jquery):
var dte = // drag table elements
{
init: function() {
var chkbx = $('.group input[type="checkbox"]:checkbox');
//var chkbx = $('#accordion');
for (var i = 0, ii = chkbx.length; i < ii; i++) {
$(chkbx).bind("click", dte.adjustList);
}
},
adjustList: function(event) {
var list = [];
var str = '';
var eleval = event.currentTarget.value;
var eleid = event.currentTarget.id;
if (eleval == 1) {
list.push(eleid);
str = '<li>' + eleid + '</li>';
}
$('#vertical ul').append(str);
/*
//var ele = event.currentTarget.id;
var allVals = [];
var str = '';
//var obj = $("#"+ele);
var ele = $('#accordion');
$(obj+': checked').each(function(){
allVals.push($(this.val()));
dte.list.push($(this.val()));
str += '<li>'+$(this.val())+'</li>';
});
$('#verticle').text(str);
alert('List: ' + toString(list));
*/
}
};
dte.init();
init: function() {
$('.group input:checkbox').bind("click", dte.adjustList);
},
you only need to bind once based on your selector.
init: function() {
var chkbx = $('.group input[type="checkbox"]:checkbox');
$(chkbx).bind("click", dte.adjustList);
},
fiddle
I have edited your fiddle, I removed the for loop. Here is the link updated fiddle
You only need to bind the click event once.
You are binding events multiple time. You can do something like this:
init:function(){
$('.group input[type="checkbox"]:checkbox').bind('click',dte.adjustList);
},
Edited your fiddle:
http://jsfiddle.net/emphaticsunshine/tPAmc/

How to pass this parameter to this function?

Here is my function:
function updateRecord(id, textEl) {
db.transaction(function(tx) {
tx.executeSql("UPDATE products SET product = ? WHERE id = ?", [textEl.innerHTML, id], null, onError);
});
}
Here is the call:
<span contenteditable="true" onkeyup="updateRecord('+item['id']+', this)">'+
item['product'] + '</span>
I would like to add a parameter to the call so that I can use the function for multiple columns. Here is what I'm trying but it doesn't work:
<span contenteditable="true" onkeyup="updateRecord('+item['id']+', "product", this)">'+
item['product'] + '</span>
function updateRecord(id, column, textEl) {
db.transaction(function(tx) {
tx.executeSql("UPDATE products SET " + column + " = ? WHERE id = ?", [textEl.innerHTML, id], null, onError);
});
}
They should do the exact same thing, I only specified the product column in the call instead of in the function. Is my syntax incorrect, am I missing something?
Edit:
Here is the full function in which the call is located:
// select all records and display them
function showRecords() {
document.getElementById('results').innerHTML = '';
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM products", [], function(tx, result) {
for (var i = 0, item = null; i < result.rows.length; i++) {
item = result.rows.item(i);
document.getElementById('results').innerHTML +=
'<li><span contenteditable="true" onkeyup="updateRecord('+item['id']+', "product", this)">'+
item['product'] + '</span> x</li>';
}
});
});
}
Update: Ok, then the issue only lies in using double quotes for product. Use single quotes and escape them:
document.getElementById('results').innerHTML +=
'<li><span contenteditable="true" onkeyup="updateRecord('+item['id']+', \'product\', this)">' + ...;
But you really should consider to refactor your code. E.g. you could write it like this:
var results = document.getElementById('results');
var container = document.createDocumentFragment();
for (var i = 0, l = result.rows.length; i < l; i++) {
var item = result.rows.item(i);
var li = document.createElement('li');
var span = document.createElement('span');
span.setAttribute('contenteditable', 'true');
span.onkeyup = (function(item) {
return function() {
updateRecord(item['id'], 'product', this);
}
}(item));
span.innerHTML = item['product'];
var a = document.createElement('a');
a.href = '#';
a.onclick = (function(item) {
return function() {
deleteRecord(item['id'])
}
}(item));
a.innerHTML = 'x';
li.appendChild(span);
li.appendChild(a);
container.appendChild(li);
}
results.appendChild(container);
It is more code but easier to maintain in the long run...
You have syntax and quotation issues. This should work:
onkeyup="updateRecord('item[\'id\']', 'product', this)"
But the code seems a bit weird to me. Is this in your actual HTML or are you echoing or printing it? Because
<span...>'+ item['product'] + '</span>
looks weird in HTML. It will literally put '+ item['product'] + ' inside the <span> tag. Please post a more complete version of your code.

Categories