I have a js file that is supposed to create a list of things with a delete button
The list gets created, and the first time that an element is deleted, it works fine. However, when I click on the delete button the second time, nothing happens. Why is this?
let sales = [{
"salesperson": "James D. Halpert",
"client": "Shake Shack",
"reams": 100
},
{
"salesperson": "Stanley Hudson",
"client": "Toast",
"reams": 400
},
{
"salesperson": "Michael G. Scott",
"client": "Computer Science Department",
"reams": 1000
},
];
function makeEntries(sales) {
$("#main").empty()
$.each(sales, function(index, value) {
var outer = $("<div class='main-page'>")
var start = $("<div class='start'></div>")
start.html(value["salesperson"])
var nameAttr = index;
var mid1 = $("<div class='mid-1'></div>")
mid1.html(value["client"])
var mid2 = $("<div class='mid-2'></div>")
mid2.html(value["reams"])
var ends1 = $("<div class='ends'>")
var ends = $("<button class='delete-button' id='" + nameAttr + "'></button></div>")
outer.append(start)
outer.append(mid1)
outer.append(mid2)
outer.append(ends1)
outer.append(ends)
$("#main").prepend(outer)
})
}
$(document).ready(function() {
makeEntries(sales)
console.log("does this get hoisted?")
console.log(sales)
$(".delete-button").click(function() {
names = Number(this.id)
sales.splice(names, 1)
makeEntries(sales)
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="main"></div>
You need an updated index of the Object in Array.
The simplest way to achieve it is: sales.splice(sales.indexOf(item), 1);
Don't rebuild your entire elements again and again. Just remove that single one both from DOM and Array.
Regarding your code, here's a better way to code it using jQuery:
const sales = [{
salesperson: "James D. Halpert",
client: "Shake Shack",
reams: 100,
}, {
salesperson: "Stanley Hudson",
client: "Toast",
reams: 400,
}, {
salesperson: "Michael G. Scott",
client: "Computer Science Department",
reams: 1000,
}];
const $main = $("#main");
const makeEntries = (sales) => {
const outers = sales.map(item => {
const $outer = $("<div>", {class:"outer"});
const $person = $("<div>", {text: item.salesperson, class: "start", appendTo: $outer});
const $client = $("<div>", {text: item.client, class: "mid-1", appendTo: $outer});
const $reams = $("<div>", {text: item.reams, class: "mid-2", appendTo: $outer});
const $delete = $("<button>", {
text: "Delete",
class: "delete-button",
appendTo: $outer,
on: {
click() {
sales.splice(sales.indexOf(item), 1);
$outer.remove();
console.log(sales);
}
}
});
return $outer;
});
$main.empty().append(outers);
};
jQuery($ => {
makeEntries(sales);
});
#main { display: flex; }
.outer {flex: 1; padding: 10px; border: 1px solid #aaa;}
<main id="main"></main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You rewrite the list each time but only add the eventlistener the very first time
Instead delegate
$("#main").on("click",".delete-button", function() {
const names = Number(this.id);
sales.splice(names, 1);
makeEntries(sales)
})
let sales = [{
"salesperson": "James D. Halpert",
"client": "Shake Shack",
"reams": 100
},
{
"salesperson": "Stanley Hudson",
"client": "Toast",
"reams": 400
},
{
"salesperson": "Michael G. Scott",
"client": "Computer Science Department",
"reams": 1000
},
];
function makeEntries(sales) {
$("#main").empty()
$.each(sales, function(index, value) {
var outer = $("<div class='main-page'>")
var start = $("<div class='start'></div>")
start.html(value["salesperson"])
var nameAttr = index;
var mid1 = $("<div class='mid-1'></div>")
mid1.html(value["client"])
var mid2 = $("<div class='mid-2'></div>")
mid2.html(value["reams"])
var ends1 = $("<div class='ends'>")
var ends = $("<button class='delete-button' id='" + nameAttr + "'></button></div>")
outer.append(start)
outer.append(mid1)
outer.append(mid2)
outer.append(ends1)
outer.append(ends)
$("#main").prepend(outer)
})
}
$(document).ready(function() {
makeEntries(sales)
console.log("does this get hoisted?")
console.log(sales)
$("#main").on("click",".delete-button", function() {
const names = Number(this.id);
sales.splice(names, 1);
makeEntries(sales)
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="main"></div>
Alternatively do not rewrite
$(".delete-button").on("click", function() {
const names = Number(this.id);
sales.splice(names, 1);
$(this).closest(".main-page").remove()
})
let sales = [{
"salesperson": "James D. Halpert",
"client": "Shake Shack",
"reams": 100
},
{
"salesperson": "Stanley Hudson",
"client": "Toast",
"reams": 400
},
{
"salesperson": "Michael G. Scott",
"client": "Computer Science Department",
"reams": 1000
},
];
function makeEntries(sales) {
$("#main").empty()
$.each(sales, function(index, value) {
var outer = $("<div class='main-page'>")
var start = $("<div class='start'></div>")
start.html(value["salesperson"])
var nameAttr = index;
var mid1 = $("<div class='mid-1'></div>")
mid1.html(value["client"])
var mid2 = $("<div class='mid-2'></div>")
mid2.html(value["reams"])
var ends1 = $("<div class='ends'>")
var ends = $("<button class='delete-button' id='" + nameAttr + "'></button></div>")
outer.append(start)
outer.append(mid1)
outer.append(mid2)
outer.append(ends1)
outer.append(ends)
$("#main").prepend(outer)
})
}
$(document).ready(function() {
makeEntries(sales)
console.log("does this get hoisted?")
console.log(sales)
$(".delete-button").on("click", function() {
const names = Number(this.id);
sales.splice(names, 1);
$(this).closest(".main-page").remove()
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="main"></div>
Related
I need datatables that can have nested rows dynamically created based on the data.
Something like this but with unlimited nested rows:
https://jsfiddle.net/dyv4L8bp/4/
Here is the code I have tried so far (taken from an example I found):
function fnFormatDetails(table_id, html) {
var sOut = "<table id=\"exampleTable_" + table_id + "\">";
sOut += html;
sOut += "</table>";
return sOut;
}
//////////////////////////////////////////////////////////// EXTERNAL DATA - Array of Objects
var terranImage = "https://i.imgur.com/HhCfFSb.jpg";
var jaedongImage = "https://i.imgur.com/s3OMQ09.png";
var grubbyImage = "https://i.imgur.com/wnEiUxt.png";
var stephanoImage = "https://i.imgur.com/vYJHVSQ.jpg";
var scarlettImage = "https://i.imgur.com/zKamh3P.jpg";
// DETAILS ROW A
var detailsRowAPlayer1 = { pic: jaedongImage, name: "Jaedong", team: "evil geniuses", server: "NA" };
var detailsRowAPlayer2 = { pic: scarlettImage, name: "Scarlett", team: "acer", server: "Europe" };
var detailsRowAPlayer3 = { pic: stephanoImage, name: "Stephano", team: "evil geniuses", server: "Europe" };
var detailsRowA = [ detailsRowAPlayer1, detailsRowAPlayer2, detailsRowAPlayer3 ];
// DETAILS ROW B
var detailsRowBPlayer1 = { pic: grubbyImage, name: "Grubby", team: "independent", server: "Europe" };
var detailsRowB = [ detailsRowBPlayer1 ];
// DETAILS ROW C
var detailsRowCPlayer1 = [{ pic: terranImage, name: "Bomber", team: "independent", server: "NA" }];
var rowA = { race: "Zerg", year: "2014", total: "3", details: detailsRowA};
var rowB = { race: "Protoss", year: "2014", total: "1", details: detailsRowB};
var rowC = { race: "Terran", year: "2014", total: "1", details: detailsRowCPlayer1};
var newRowData = [rowA, rowB, rowC] ;
////////////////////////////////////////////////////////////
var iTableCounter = 1;
var oTable;
var oInnerTable;
var detailsTableHtml;
//Run On HTML Build
$(document).ready(function () {
// you would probably be using templates here
detailsTableHtml = $("#detailsTable").html();
//Insert a 'details' column to the table
var nCloneTh = document.createElement('th');
var nCloneTd = document.createElement('td');
nCloneTd.innerHTML = '<img src="http://i.imgur.com/SD7Dz.png">';
nCloneTd.className = "center";
$('#exampleTable thead tr').each(function () {
this.insertBefore(nCloneTh, this.childNodes[0]);
});
$('#exampleTable tbody tr').each(function () {
this.insertBefore(nCloneTd.cloneNode(true), this.childNodes[0]);
});
//Initialse DataTables, with no sorting on the 'details' column
var oTable = $('#exampleTable').dataTable({
"bJQueryUI": true,
"aaData": newRowData,
"bPaginate": false,
"aoColumns": [
{
"mDataProp": null,
"sClass": "control center",
"sDefaultContent": '<img src="http://i.imgur.com/SD7Dz.png">'
},
{ "mDataProp": "race" },
{ "mDataProp": "year" },
{ "mDataProp": "total" }
],
"oLanguage": {
"sInfo": "_TOTAL_ entries"
},
"aaSorting": [[1, 'asc']]
});
/* Add event listener for opening and closing details
* Note that the indicator for showing which row is open is not controlled by DataTables,
* rather it is done here
*/
$('#exampleTable tbody td img').live('click', function () {
var nTr = $(this).parents('tr')[0];
var nTds = this;
if (oTable.fnIsOpen(nTr)) {
/* This row is already open - close it */
this.src = "http://i.imgur.com/SD7Dz.png";
oTable.fnClose(nTr);
}
else {
/* Open this row */
var rowIndex = oTable.fnGetPosition( $(nTds).closest('tr')[0] );
var detailsRowData = newRowData[rowIndex].details;
this.src = "http://i.imgur.com/d4ICC.png";
oTable.fnOpen(nTr, fnFormatDetails(iTableCounter, detailsTableHtml), 'details');
oInnerTable = $("#exampleTable_" + iTableCounter).dataTable({
"bJQueryUI": true,
"bFilter": false,
"aaData": detailsRowData,
"bSort" : true, // disables sorting
"aoColumns": [
{ "mDataProp": "pic" },
{ "mDataProp": "name" },
{ "mDataProp": "team" },
{ "mDataProp": "server" }
],
"bPaginate": false,
"oLanguage": {
"sInfo": "_TOTAL_ entries"
},
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var imgLink = aData['pic'];
var imgTag = '<img width="100px" src="' + imgLink + '"/>';
$('td:eq(0)', nRow).html(imgTag);
return nRow;
}
});
iTableCounter = iTableCounter + 1;
}
});
});
Can someone send me an example. Please dont send examples with a single nested row only. I need unlimited ones.
Hi (sorry for my english), I have this script:
<script type="text/javascript">
$(document).ready(function() {
var idPlato = decodeURI(getUrlVars()["idPl"]);
var url = "http://localhost/plato-datos.php?idPla="+idPlato+"";
});
};
</script>
It brings me this json from my database:
[{"category":"first","name":"green","idP":"1", "count":3},
{"category":"first","name":"blue","idP":"2","count":5},
{"category":"sec","name":"peter","idP":"3", "count":3},
{"category":"sec","name":"james","idP":"4", "count":2,},
{"category":"third","name":"dog","idP":"5", "count":4}]
I need to create one radiobuton for every name and group by categores
I create a solution. Kinda ugly but it will work:
var data = [{
"category": "first",
"name": "green",
"idP": "1",
"count": 3
}, {
"category": "first",
"name": "blue",
"idP": "2",
"count": 5
}, {
"category": "sec",
"name": "peter",
"idP": "3",
"count": 3
}, {
"category": "sec",
"name": "james",
"idP": "4",
"count": 2,
}, {
"category": "third",
"name": "dog",
"idP": "5",
"count": 4
}];
var result = {};
data.map(a => {
if (result[a.category]) {
result[a.category].push(a.name);
} else {
result[a.category] = [a.name];
}
});
Object.keys(result).map(category => {
var select = document.createElement('select');
result[category].map(name => {
var option = document.createElement('option');
option.value = name;
option.text = name;
select.appendChild(option);
});
document.body.appendChild(select);
});
Im working with jquery mobile then i used autodividersSelector function for group by the category JSON object, and build a radiobuton for every name
<script type="text/javascript">
//catch the JSON from my database
$(document).ready(function() {
var idPla = decodeURI(getUrlVars()["idPl"]);
var urlAder =
"http://localhost/lista-adereso.php?idPla=" + idPla + "";
//print the radiobutons
$.getJSON(urlAder, function(resultado) {
var allfiles = '';
for (var i = 0, aderesos = null; i <
resultado.length; i++) {
aderesos = resultado[i];
allfiles +='<li><label><input type="radio" data-
status="' + aderesos.aderesoCatNom +'"
name="name" id="id" value="' +
aderesos.aderNombre +'">'+
aderesos.aderNombre + '</label></li>'; }
//Group by categories
$('#linkList')
.empty()
.append(allfiles)
.listview({
autodividers:true,
autodividersSelector: function ( li ) {
var out = li.find('input').data("status");
return out;
}
})
.listview("refresh");
});
});
</script>
Demo
I am using this solution to load dynamic data in to Data Table. I have to use the Array of Array since I am getting dynamic data from user on font end selection (NO DATABASE Selection).
I am using following code to upload data into the table
<table cellpadding="0" cellspacing="0" border="0" class="dataTable" id="example"></table>
and JS:
$(document).ready(function () {
var counter = 0;
var compareTable = [];
var compareRow = [];
var check = "Test";
var compModelName = "Test";
var selectedType = "Test";
var selectedTarget = "Test";
var selectedROR = "Test";
var selectedSpecies = "Test";
var historicDis = "Test";
var projectsNumber = "Test";
var projectsCost = "Test";
var projectsRoads = "Test";
var projectsPowerline = "Test";
var projectsPenstock = "Test";
var mapshow = "Test";
$("#load").on("click", function () {
loader();
});
function loader() {
compareRow.push(check);
compareRow.push(compModelName);
compareRow.push(selectedType);
compareRow.push(selectedTarget);
compareRow.push(selectedROR);
compareRow.push(selectedSpecies);
compareRow.push(historicDis);
compareRow.push(projectsNumber);
compareRow.push(projectsCost);
compareRow.push(projectsRoads);
compareRow.push(projectsPowerline);
compareRow.push(projectsPenstock);
compareRow.push(mapshow);
}
$('#example').dataTable( {
"data": compareTable,
"columns": [
{ "title": "Compare" },
{ "title": "Model Name" },
{ "title": "Model Type" },
{ "title": "Energy Target" },
{ "title": "ROR Attribute" },
{ "title": "Species", "class": "center" },
{ "title": "Disturbance", "class": "center" },
{ "title": "Projects" },
{ "title": "Cost (M$)" },
{ "title": "Roads (Km)" },
{ "title": "Powerlines (Km)", "class": "center" },
{ "title": "Penstock (m)", "class": "center" },
{ "title": "Map" }
]
} );
});
});
but as you can see in the Demo it is not functioning when we click on the "#load". Can you please let me know why this is happening and how I can fix it?
Number of autocomplete search box is dynamic based an #AddButton. Autocomplete is working, but when I select the values, it doesnt rendered it properly. Please tell me where Am I missing.
Fiddle setup is at http://jsfiddle.net/jakenrush/kELm3/1/
Jquery code below
$(function() {
var projects = [
{
"label": "ajax",
"value": "1003",
"desc": "foriegn"
},
{
"label": "jquery",
"value": "1000",
"desc": "dd"
},
{
"label": "wordpress theme",
"value": "1000",
"desc": "h"
},
{
"label": "xml",
"value": "1000",
"desc": "j"
}];
$("#addButton");
var counter = 13;
$("#addButton").click(function() {
var newTextBoxDiv = $(document.createElement('div'))
.attr("id", 'TextBoxDiv' + counter);
var roleInput = $('<input/>', {
type: 'text',
placeholder: 'Role',
name: 'Role' + counter,
id: 'project-description' + counter
});
var searchInput = $('<input/>', {
type: 'text',
placeholder: 'search',
name: 'search' + counter,
id: 'project' + counter
});
var hidd = $('<input/>', {
type: 'hidden',
name: 'searchhid' + counter,
id: 'project-id' + counter
});
newTextBoxDiv.append(roleInput).append(searchInput).append(hidd);
newTextBoxDiv.appendTo("#TextBoxesGroup");
$("#project" + counter).autocomplete({
minLength: 0,
source: projects,
focus: function(event, ui) {
$("#project" + counter).val(ui.item.label);
return false;
},
select: function(event, ui) {
$("#project" + counter).val(ui.item.label);
$("#project-id" + counter).val(ui.item.value);
$("#project-description" + counter).val(ui.item.value);
$("#project-icon" + counter).attr("src", "images/" + ui.item.icon);
return false;
}
})
counter++;
});
});
html code :
<div id="project-label"></div>
<input type="hidden" id="project-id" />
<div id='TextBoxesGroup'>
<div id="TextBoxDiv1" class="form-inline control-group">
</div>
</div>
<input type='button' value='Add' id='addButton' />
i have update your fiddle and it is working, the problem is with your counter variable which never been incremented, because you have place at end of script, but you have return statement above it.
your fiddle here http://jsfiddle.net/kELm3/6/
var counter = 0;
$("#addButton").click(function() {
counter++;
Given json like this :
{ "rss": {
"page": 1,
"results": [{
"type": "text",
"$": 10
}],
"text": [{
"content": "Lorem ipsum dolor sit amet.",
"author": {
"name": "Cesar",
"email": "cesar#evoria.com"
},
},
{
"content": "Tema Tis rolod muspi merol.",
"author": {
"name": "Cleopatre",
"email": "cleopatre#pyramid.com"
},
}]
}
In javascript, I can retrieve value like this :
var json = JSON.parse(datajson);
$.each(json.text, function(key, val) {
// this one is ok
var content = val['content'];
// this one does not work
var authorname = val['author.name'];
});
Is this a way, given the attribute name in a string format, to retrieve the value of a complex object, for instance json.text[0].author.name?
EDIT
I would like to store the needed attributes in another object like :
[
{ dt: "Text content", dd: "content" },
{ dt: "Author name", dd: "author.name"}
]
You can split your "index" by . and loop over "segments", descending through levels on each iteration.
var obj = {
author : {
name : "AuthorName"
}
}
function get_deep_index(obj, index) {
var segments = index.split('.')
var segments_len = segments.length
var currently_at = obj
for(var idx = 0; idx < segments_len; idx++) {
currently_at = currently_at[segments[idx]]
}
return currently_at
}
console.log(get_deep_index(obj, 'author.name'))
The following should fix the problem.
var authorname = val['author']['name'];
You can also store the object itself as:
var author = val['author'];
And then later on you can index the attributes from that.
console.log(author.name, author.email)
Yent give a good hint in the comments with the eval function. I resolve my needed with this kind of code:
var json = JSON.parse(myjsonasastring);
var descriptiontobeadded = [
{ dt: "Text content", dd: "content" },
{ dt: "Author name", dd: "author.name" }
];
$.each(descriptiontobeadded, function(key, val) {
var dt = '<dt>' + val.dt + '</dt>';
description.append(dt);
var dl = '<dd>' + eval('json.' + val.dd) + '</dd>';
description.append(dl);
});